package jasypt;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 参数排序加密签名
 *
 * @author zhangtao
 * @date 2021/11/30
 */
public class SortSignEncryptHandler {

    public Object handle(Object proceed, long timeout, TimeUnit timeUnit, String sortSignSecret,
                         Map<Object, Object> jsonMap) throws Exception {
        Object sign = jsonMap.get("sign");
        Object timestamp = jsonMap.get("timestamp");
        this.checkParam(sign, timestamp, timeout, timeUnit);
        String digestMd5 = this.getDigest(jsonMap, sortSignSecret, StandardCharsets.UTF_8);
        System.out.println("加密后的字符：" + digestMd5);
        if (!digestMd5.equals(sign)) {
            throw new Exception("Illegal request,Decryption failed");
        }
        return proceed;
    }

    private void checkParam(Object sign, Object timestamp, long timeout, TimeUnit timeUnit) throws Exception {
        if (sign == null) {
            throw new Exception("Illegal request,Sign does not exist");
        }
        if (timestamp == null) {
            throw new Exception("Illegal request,timestamp does not exist");
        }
        long now = System.currentTimeMillis();
        Long timestampLong = Long.valueOf(timestamp.toString());
        if (!((now < timestampLong + timeout) && now >= timestampLong)) {
            throw new Exception("Illegal request,request timeout");
        }
    }

    private String getDigest(Map<Object, Object> map, String sortSignSecret, Charset charset) throws Exception {
        StringBuilder sb = new StringBuilder();
        map.entrySet().stream().
                filter(entry -> entry != null && !entry.getKey().equals("sign")).
                sorted(Comparator.comparing(entry -> entry.getKey().toString())).
                forEach(entry -> {
                    sb.append(entry.getKey().toString()).append("=").append(entry.getValue().toString()).append("&");
                });
        sb.append("secret").append("=").append(sortSignSecret);
        return md5Encode(sb.toString());
    }

    private String md5Encode(String plainText) throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            return buf.toString();
        } catch (Exception e) {
            throw new Exception("md5 encode error");
        }
    }
}
